﻿using PetaPoco;
using PetaPoco.Core;
using System.Runtime.CompilerServices;

namespace BlazorAdmin.Extensions
{
    /// <summary>
    /// Oracle数据库实现类
    /// </summary>
    internal class OracleBatchProvider : BatchProvider
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="db">IDatabase 实例</param>
        public OracleBatchProvider(IDatabase db) : base(db)
        { }

        //
        // 摘要:
        //     拼接字符串方法具体实现
        //
        // 参数:
        //   pd:
        //
        //   pocos:
        //
        // 类型参数:
        //   T:
        protected override void InsertBatch<T>(PocoData pd, IEnumerable<T> pocos)
        {
            PocoData pd2 = pd;
            try
            {
                string primaryKeyName = pd2.TableInfo.PrimaryKey;
                bool autoIncrement = pd2.TableInfo.AutoIncrement;
                IProvider _provider = Database.Provider;
                List<object> args = new();
                List<string> batchSql = new();
                Database.BeginTransaction();
                int index = 0;
                pocos.ToList().ForEach(delegate (T poco)
                {
                    List<string> list = new();
                    List<string> list2 = new();
                    foreach (KeyValuePair<string, PocoColumn> column in pd2.Columns)
                    {
                        if (!column.Value.ResultColumn)
                        {
                            if (autoIncrement && primaryKeyName != null && primaryKeyName.Equals(column.Key, StringComparison.OrdinalIgnoreCase))
                            {
                                if (index == 0)
                                {
                                    string autoIncrementExpression = _provider.GetAutoIncrementExpression(pd2.TableInfo);
                                    if (autoIncrementExpression != null)
                                    {
                                        index = Database.ExecuteScalar<int>("select " + autoIncrementExpression + " from dual", Array.Empty<object>());
                                        if (index == 0)
                                        {
                                            throw new Exception("");
                                        }
                                    }
                                }

                                list.Add(Database.Provider.EscapeTableName(column.Key));
                                list2.Add(index.ToString());
                                index++;
                            }
                            else
                            {
                                list.Add(_provider.EscapeSqlIdentifier(column.Key));
                                string? value = ConvertValue(column.Value.GetValue(poco), args);
                                if (!string.IsNullOrEmpty(value))
                                    list2.Add(value);
                            }
                        }
                    }

                    if (batchSql.Count == 0)
                    {
                        batchSql.Add("INSERT ALL");
                    }

                    batchSql.Add(GenerateBodySql(Database.Provider.EscapeTableName(pd2.TableInfo.TableName), list.ToArray(), list2.ToArray()));
                    if (batchSql.Count == BatchSize)
                    {
                        InsertIntoDb(batchSql, args);
                    }
                });
                if (batchSql.Count > 0)
                {
                    InsertIntoDb(batchSql, args);
                }

                if (index != 0 && pocos.Count() > 1)
                {
                    string sequenceName = pd2.TableInfo.SequenceName;
                    IDatabase database = Database;
                    DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new(29, 2);
                    defaultInterpolatedStringHandler.AppendLiteral("ALTER SEQUENCE ");
                    defaultInterpolatedStringHandler.AppendFormatted(sequenceName);
                    defaultInterpolatedStringHandler.AppendLiteral(" INCREMENT BY ");
                    defaultInterpolatedStringHandler.AppendFormatted(pocos.Count() - 1);
                    database.Execute(defaultInterpolatedStringHandler.ToStringAndClear());
                    Database.ExecuteScalar<int>("SELECT " + sequenceName + ".NEXTVAL FROM DUAL", Array.Empty<object>());
                    _ = Database.Execute("ALTER SEQUENCE " + sequenceName + " INCREMENT BY 1");
                }

                Database.CompleteTransaction();
            }
            catch (Exception)
            {
                Database.AbortTransaction();
                throw;
            }
        }

        protected override void InsertIntoDb(List<string> sqls, List<object> args)
        {
            sqls.Add(" select 1 from dual");
            base.InsertIntoDb(sqls, args);
        }

        /// <summary>
        /// 生成插入语句方法
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="names"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        protected static string GenerateBodySql(string tableName, string[] names, string[] values)
        {
            DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new(19, 3);
            defaultInterpolatedStringHandler.AppendLiteral(" INTO ");
            defaultInterpolatedStringHandler.AppendFormatted(tableName);
            defaultInterpolatedStringHandler.AppendLiteral(" (");
            defaultInterpolatedStringHandler.AppendFormatted(string.Join(",", names));
            defaultInterpolatedStringHandler.AppendLiteral(") Values (");
            defaultInterpolatedStringHandler.AppendFormatted(string.Join(",", values));
            defaultInterpolatedStringHandler.AppendLiteral(")");
            return defaultInterpolatedStringHandler.ToStringAndClear();
        }
    }
}
